
#ifndef _TTG_SERVICES_DLLLOADER_
#define _TTG_SERVICES_DLLLOADER_
#include "Common/Definitions.h"

#include <windows.h>
#include <list>
#include "Common/Structures.h"
#include "Runtime.Low/Services/Service.h"

namespace ttg
{
	namespace services
	{
		//Named record for DllLoader about one dll.
		//Contains names of loaded functions and reference to instance.
		class DllLoaderRec :public structures::NamedObject
		{
			private:
				structures::Dictionary<structures::NamedObject> *methods;
				HMODULE ref;
			public:
				//Creates record with given name and instance.
				//Note: it suppress GC.
				inline DllLoaderRec(const char *name, HMODULE module)
					:NamedObject(name)
				{
					this->ref = module;
					methods = structures::Dictionary<structures::NamedObject>::create(30);
				}
				//Returns reference to instance.
				inline HMODULE getRef()
						{ return ref; }
				//Returns true, if function with name is loaded.
				inline bool isLoaded(const char *name)
						{ return methods->get(name) != NULL; }
				//Adds record about function. Now it's "isLoaded".
				inline void add(const char *name)
						{ methods->add(new structures::NamedObject(name)); }
				//Releases record.
				//Note: All references to instances must be deleted by upper level.
				virtual ~DllLoaderRec()
						{ delete methods; }
		};

		//Loads required dll and releases them.
		class DllLoader :public Service
		{
			private:
				static DllLoader *ref;
			private:
				structures::Dictionary<DllLoaderRec> *dlls;
				DllLoader();
			protected:
				virtual void startUnSafe(std::vector<Service *> &deps, const char *params);
				virtual void stopUnSafe();
			public:
				//Tries to load given dll, and bind given func given to variable.
				//If it has been already loaded, does nothing.
				void load(const char *dllname, const char *funcname, FARPROC &funcaddr);
				//Returns reference to instance (which always exists).
				inline static DllLoader *getRef()
				{ return ref == NULL ? (ref = new DllLoader()) : ref; }
		};
	}
}

#endif
